<pre class='metadata'>
Title: WebGPU
Shortname: webgpu
Level: 1
Status: w3c/ED
Group: webgpu
URL: https://gpuweb.github.io/gpuweb

!Participate: <a href="https://github.com/gpuweb/gpuweb/issues/new">File an issue</a> (<a href="https://github.com/gpuweb/gpuweb/issues">open issues</a>)

Editor: Dzmitry Malyshau, Mozilla https://www.mozilla.org, dmalyshau@mozilla.com
Editor: Justin Fan, Apple https://www.apple.com, justin_fan@apple.com
Editor: Kai Ninomiya, Google http://www.google.com, kainino@google.com
Abstract: WebGPU exposes an API for performing operations, such as rendering and computation, on a Graphics Processing Unit.
Markup Shorthands: markdown yes
</pre>

<pre class='anchors'>
urlPrefix: https://tc39.github.io/ecma262/; spec: ECMA-262
    type: dfn
        text: agent; url: agent
</pre>


Introduction {#intro}
=====================

This specification rocks.


Type Definitions {#type-definitions}
============================

<script type=idl>
typedef unsigned long GPUFlags;
typedef unsigned long long GPUBufferSize;
</script>

## Colors and Vectors ## {#colors-and-vectors}

<script type=idl>
dictionary GPUColorDict {
    required double r;
    required double g;
    required double b;
    required double a;
};
typedef (sequence<double> or GPUColorDict) GPUColor;
</script>

Note: `double` is large enough to precisely hold 32-bit signed/unsigned
integers and single-precision floats.

<script type=idl>
dictionary GPUOrigin2DDict {
    unsigned long x = 0;
    unsigned long y = 0;
};
typedef (sequence<unsigned long> or GPUOrigin2DDict) GPUOrigin2D;
</script>

<script type=idl>
dictionary GPUOrigin3DDict {
    unsigned long x = 0;
    unsigned long y = 0;
    unsigned long z = 0;
};
typedef (sequence<unsigned long> or GPUOrigin3DDict) GPUOrigin3D;
</script>

<script type=idl>
dictionary GPUExtent3DDict {
    required unsigned long width;
    required unsigned long height;
    required unsigned long depth;
};
typedef (sequence<unsigned long> or GPUExtent3DDict) GPUExtent3D;
</script>

## Internal Objects ## {#webgpu-internal-objects}

An <dfn dfn>internal object</dfn> is a non-exposed conceptual WebGPU object.
[=Internal objects=] track the state of an API object and hold any underlying implementation.
If the state of a particular [=internal object=] can change in parallel from multiple [=agents=],
those changes are always atomic with respect to all [=agents=].

Note: An "[=agent=]" refers to a JavaScript "thread" (i.e. main thread, or Web Worker).

## WebGPU Interfaces ## {#webgpu-interfaces}

A <dfn dfn>WebGPU interface</dfn> is an exposed interface which encapsulates an [=internal object=].
It provides the interface through which the [=internal object=]'s state is changed.

Any interface which includes {{GPUObjectBase}} is a [=WebGPU interface=].

<script type=idl>
interface mixin GPUObjectBase {
    attribute DOMString? label;
};
</script>

<dl dfn-type=attribute dfn-for=GPUObjectBase>
    : <dfn>label</dfn>
    ::

    : <dfn>\[[device]]</dfn>, of type [=device=], readonly
    ::
        An internal slot holding the [=device=] on which the object exists.
</dl>

## Object Descriptors ## {#object-descriptors}

<script type=idl>
dictionary GPUObjectDescriptorBase {
    DOMString? label;
};
</script>


Initialization {#initialization}
================================

<script type=idl>
[Exposed=Window]
partial interface Navigator {
    [SameObject] readonly attribute GPU gpu;
};

[Exposed=DedicatedWorker]
partial interface WorkerNavigator {
    [SameObject] readonly attribute GPU gpu;
};
</script>

<script type=idl>
[Exposed=Window]
interface GPU {
    // May reject with DOMException  // TODO: DOMException("OperationError")?
    Promise<GPUAdapter> requestAdapter(optional GPURequestAdapterOptions options);
};
</script>

## Adapters ## {#adapters}

An <dfn dfn>adapter</dfn> represents an implementation of WebGPU on the system.
Each adapter identifies both an instance of a hardware accelerator (e.g. GPU or CPU) and
an instance of a browser's implementation of WebGPU on top of that accelerator.

<!--TODO: Move definition of "invalid" somewhere more generic.-->
If an [=adapter=] becomes unavailable, it becomes <dfn dfn>invalid</dfn>.
Once invalid, it never becomes valid again.

Note:
An [=adapter=] may be a physical display adapter (GPU), but it could also be
a software renderer.
A returned [=adapter=] could refer to different physical adapters, or to
different browser codepaths or system drivers on the same physical adapters.
Applications can hold onto multiple [=adapters=] at once (via {{GPUAdapter}})
(even if some are [=invalid=]),
and two of these could refer to different instances of the same physical
configuration (e.g. if the GPU reset, or were disconnected and reconnected).

### GPUAdapter ### {#gpu-adapter}

A <dfn interface>GPUAdapter</dfn> refers to an [=adapter=],
and exposes its capabilities (extensions and limits).

<script type=idl>
interface GPUAdapter {
    readonly attribute DOMString name;
    readonly attribute GPUExtensions extensions;
    //readonly attribute GPULimits limits; Don't expose higher limits for now.

    // May reject with DOMException  // TODO: DOMException("OperationError")?
    Promise<GPUDevice> requestDevice(optional GPUDeviceDescriptor descriptor);
};
</script>

{{GPUAdapter}} has the following attributes:

<dl dfn-type=attribute dfn-for=GPUAdapter>
    : <dfn>\[[adapter]]</dfn>, of type [=adapter=], readonly
    ::
        An internal slot holding the [=adapter=] to which this {{GPUAdapter}}
        refers.

    : <dfn>name</dfn>
    ::
        A human-readable name identifying the adapter.
        The contents are implementation-defined.

    : <dfn>extensions</dfn>
    ::
        A {{GPUExtensions}} object which enumerates the extensions supported
        by the user agent, and whether each extension is supported by the
        underlying implementation.
          - If an extension is not supported by the user agent,
            it will not be present in the object.
          - If an extension is supported by the user agent, but
            not by the [=adapter=], it will be `false`.
          - If an extension is supported by the user agent and
            by the [=adapter=], it will be `true`.
</dl>

### Getting an Adapter ### {#adapter-creation}

To get a {{GPUAdapter}}, use {{GPU/requestAdapter()}}.

<script type=idl>
dictionary GPURequestAdapterOptions {
    GPUPowerPreference powerPreference;
};
</script>

<dfn dictionary>GPURequestAdapterOptions</dfn>
provides requirements and hints to the user agent indicating what
configuration is suitable for the application.

<dl dfn-type=dict-member dfn-for=GPURequestAdapterOptions>
    : <dfn>powerPreference</dfn>
    ::
        Provides a hint indicating what class of [=adapter=] should be selected from the system's
        available adapters.

        If unspecified, the user agent decides which class of adapter is most suitable.

        Note:
        This hint may influence which GPU is used in a system with multiple GPUs.
        For example, a dual-GPU system might have one GPU that consumes less power at the expense
        of performance.

        Note:
        Depending on the exact hardware configuration, such as attached displays or removable
        GPUs, the user agent may select different [=adapters=] given the same power preference.
        Typically, given the same hardware configuration and state (e.g. battery percentage) and
        `powerPreference`, the user agent should select the same adapter.
</dl>

<script type=idl>
enum GPUPowerPreference {
    "low-power",
    "high-performance"
};
</script>

<dl dfn-type=enum-value dfn-for=GPUPowerPreference>
    : <dfn>"low-power"</dfn>
    ::
        Indicates a request to prioritize power savings over performance.

        Note:
        Generally, content should use this if it is unlikely to be constrained by drawing
        performance; for example, if it renders only one frame per second, draws only relatively
        simple geometry with simple shaders, or uses a small HTML canvas element.
        Developers are encouraged to use this value if their content allows, since it may
        significantly improve battery life on portable devices.

    : <dfn>"high-performance"</dfn>
    ::
        Indicates a request to prioritize performance over power consumption.

        Note:
        By choosing this value, developers should be aware that, for [=devices=] created on the
        resulting adapter, user agents are more likely to force device loss, in order to save
        power.
        Developers are encouraged to only specify this value if they believe it is absolutely
        necessary, since it may significantly decrease battery life on portable devices.
</dl>

## Devices ## {#devices}

A <dfn dfn>device</dfn> is the logical instantiation of an [=adapter=],
through which [=internal objects=] are created.
It can be shared across multiple [=agents=] (e.g. dedicated workers).

A [=device=] is the exclusive owner of all [=internal objects=] created from it:
when the [=device=] is lost, all objects created from it become invalid.

<!-- TODO: write and link to spec about what invalid means -->

A [=device=] has the following internal slots:

<dl dfn-type=attribute dfn-for=device>
    : <dfn>\[[adapter]]</dfn>, of type [=adapter=], readonly
    ::
        The [=adapter=] from which this device was created.
</dl>

When a [=device=] is created, its capabilities are set to those requested by
the user in {{GPUAdapter/requestDevice()}} (which must be no greater than the
capabilities specified by the [=adapter=]).
These capabilities are enforced upon the usage of objects on the [=device=],
even if the underlying [=adapter=] can support higher capabilities.

<!-- TODO: specify "no greater" more precisely -->

### GPUDevice ### {#gpu-device}

A {{GPUDevice}} refers to a [=device=] and
exposes the capabilities with which the [=device=] was created.
It is the top-level object through which [=WebGPU interfaces=] are created.

<script type=idl>
[Exposed=(Window, Worker), Serializable]
interface GPUDevice : EventTarget {
    readonly attribute GPUExtensions extensions;
    readonly attribute GPULimits limits;
    readonly attribute GPUAdapter adapter;

    GPUBuffer createBuffer(GPUBufferDescriptor descriptor);
    GPUMappedBuffer createBufferMapped(GPUBufferDescriptor descriptor);
    Promise<GPUMappedBuffer> createBufferMappedAsync(GPUBufferDescriptor descriptor);
    GPUTexture createTexture(GPUTextureDescriptor descriptor);
    GPUSampler createSampler(optional GPUSamplerDescriptor descriptor);

    GPUBindGroupLayout createBindGroupLayout(GPUBindGroupLayoutDescriptor descriptor);
    GPUPipelineLayout createPipelineLayout(GPUPipelineLayoutDescriptor descriptor);
    GPUBindGroup createBindGroup(GPUBindGroupDescriptor descriptor);

    GPUShaderModule createShaderModule(GPUShaderModuleDescriptor descriptor);
    GPUComputePipeline createComputePipeline(GPUComputePipelineDescriptor descriptor);
    GPURenderPipeline createRenderPipeline(GPURenderPipelineDescriptor descriptor);

    GPUCommandEncoder createCommandEncoder(optional GPUCommandEncoderDescriptor descriptor);
    GPURenderBundleEncoder createRenderBundleEncoder(GPURenderBundleEncoderDescriptor descriptor);

    GPUQueue getQueue();
};
GPUDevice includes GPUObjectBase;
</script>

{{GPUDevice}} also has the following internal slots:

<dl dfn-type=attribute dfn-for=GPUDevice>
    : <dfn>\[[device]]</dfn>, of type [=device=], readonly
    ::
        The [=device=] that this {{GPUDevice}} refers to.
</dl>

{{GPUDevice}} objects are [=serializable objects=].

<div algorithm="serializing a GPUDevice">
    Their [=serialization steps=], given |value|, |serialized|, and |forStorage|, are:

    1. If |forStorage| is true, throw a "{{DataCloneError}}".

    1. Set |serialized|.device to the value of |value|.{{GPUDevice/[[device]]}}.
</div>

<div algorithm="deserializing a GPUDevice">
    Their [=deserialization steps=], given |serialized| and |value|, are:

    1. Set |value|.{{GPUDevice/[[device]]}} to |serialized|.device.
</div>

### Getting a Device ### {#device-creation}

To get a {{GPUDevice}}, use {{GPUAdapter/requestDevice()}}.

<script type=idl>
dictionary GPUDeviceDescriptor : GPUObjectDescriptorBase {
    GPUExtensions extensions;
    GPULimits limits;

    // TODO: are other things configurable like queues?
};
</script>

<dl dfn-type=dict-member dfn-for=GPUDeviceDescriptor>
    : <dfn>extensions</dfn>
    ::
        The extensions to request of device creation.

    : <dfn>limits</dfn>
    ::
        The limits to request of device creation.
</dl>

<div algorithm="creating a GPUDevice">
    1. If the requested configuration is not available
        (i.e. the requested extensions or limits cannot be supported),
        {{GPUAdapter/requestDevice()}} rejects with a "{{NotSupportedError}}".

    1. Otherwise, a {{GPUDevice}} is created with the {{GPUExtensions}} and {{GPULimits}} specified.
</div>

<script type=idl>
dictionary GPUExtensions {
    boolean anisotropicFiltering = false;
};
</script>

<script type=idl>
dictionary GPULimits {
    unsigned long maxBindGroups = 4;
    unsigned long maxDynamicUniformBuffersPerPipelineLayout = 8;
    unsigned long maxDynamicStorageBuffersPerPipelineLayout = 4;
    unsigned long maxSampledTexturesPerShaderStage = 16;
    unsigned long maxSamplersPerShaderStage = 16;
    unsigned long maxStorageBuffersPerPipelineLayout = 8;
    unsigned long maxStorageTexturesPerShaderStage = 4;
    unsigned long maxUniformBuffersPerShaderStage = 12;
};
</script>


# {{GPUBuffer}} # {#GPUBuffer}

A {{GPUBuffer}} represents a block of memory that can be used in GPU operations.
Data is stored in linear layout, meaning that each byte of the allocation can be
addressed by its offset from the start of the {{GPUBuffer}}, subject to alignment
restrictions depending on the operation.

{{GPUBuffer}} has the following internal slots:

<dl dfn-type=attribute dfn-for="GPUBuffer">
	: <dfn>\[[size]]</dfn> of type {{GPUBufferSize}}.
	::
        The length of the {{GPUBuffer}} allocation in bytes.

	: <dfn>\[[usage]]</dfn> of type {{GPUBufferUsageFlags}}.
	::
        The allowed usages for this {{GPUBuffer}}.

    : <dfn>\[[state]]</dfn> of type [=buffer state=].
    ::
        The current state of the {{GPUBuffer}}.
</dl>

Each {{GPUBuffer}} has a current <dfn dfn>buffer state</dfn> which is one of the following:

 - "<dfn dfn for="buffer state">mapped</dfn>" where the {{GPUBuffer}} is available for CPU operations.
 - "<dfn dfn for="buffer state">unmapped</dfn>" where the {{GPUBuffer}} is available for GPU operations.
 - "<dfn dfn for="buffer state">destroyed</dfn>" where the {{GPUBuffer}} is no longer available for any operations except {{GPUBuffer/destroy}}.

Note:
{{GPUBuffer/[[size]]}} and {{GPUBuffer/[[usage]]}} are immutable once the {{GPUBuffer}} has been created.

## Creation ## {#buffer-creation}

A {{GPUBuffer}} can be created in the "[=buffer state/unmapped=]" state using the {{GPUDevice}}.{{GPUDevice/createBuffer(descriptor)}} method.

### {{GPUBufferDescriptor}} ### {#GPUBufferDescriptor}

This specifies the options to use in creating a {{GPUBuffer}}.

<script type=idl>
dictionary GPUBufferDescriptor : GPUObjectDescriptorBase {
    required GPUBufferSize size;
    required GPUBufferUsageFlags usage;
};
</script>

<!-- TODO(kangz): Describe what are the {{device}} [[allowed buffer usages]] -->

<dl dfn-type="abstract-op">
    : <dfn>validating GPUBufferDescriptor</dfn>(device, descriptor)
    ::
        <div algorithm="validation GPUBufferDescriptor(device, descriptor)">
            1. If device is lost return false.
            1. If any of the bits of |descriptor|'s {{GPUBufferDescriptor/usage}} aren't present in this device's [[allowed buffer usages]] return false.
            1. If both the {{GPUBufferUsage/MAP_READ}} and {{GPUBufferUsage/MAP_WRITE}} bits of |descriptor|'s {{GPUBufferDescriptor/usage}} attribute are set, return false.
            1. Return true.
        </div>
</dl>

### {{GPUDevice/createBuffer(descriptor)|GPUDevice.createBuffer(descriptor)}} ### {#GPUDevice-createBuffer}

<dl dfn-type="method" dfn-for="GPUDevice">
	: <dfn>createBuffer(descriptor)</dfn>
	::
		<div algorithm="GPUDevice.createBuffer(descriptor)">
            1. If the result of [$validating GPUBufferDescriptor$](this, descriptor) is false:

                1. Record a validation error in the current scope.
                <!-- TODO(kangz): Once we have a description of the error monad, explain what the error buffer is. -->
                1. Create an error buffer and return the result.

            1. Let |b| be a new {{GPUBuffer}} object.
            1. Set the {{GPUBuffer/[[size]]}} slot of |b| to the value of the {{GPUBufferDescriptor/size}} attribute of |descriptor|.
            1. Set the {{GPUBuffer/[[usage]]}} slot of |b| to the value of the {{GPUBufferDescriptor/usage}} attribute of |descriptor|.
            1. Set the {{GPUBuffer/[[state]]}} internal slot of |b| to `"unmapped"`.
            1. Set each byte of |b|'s allocation to zero.
            1. Return |b|.
        </div>
</dl>

## Buffer Usage ## {#buffer-usage}

<script type=idl>
typedef GPUFlags GPUBufferUsageFlags;
interface GPUBufferUsage {
    const GPUFlags NONE      = 0x0000;
    const GPUFlags MAP_READ  = 0x0001;
    const GPUFlags MAP_WRITE = 0x0002;
    const GPUFlags COPY_SRC  = 0x0004;
    const GPUFlags COPY_DST  = 0x0008;
    const GPUFlags INDEX     = 0x0010;
    const GPUFlags VERTEX    = 0x0020;
    const GPUFlags UNIFORM   = 0x0040;
    const GPUFlags STORAGE   = 0x0080;
    const GPUFlags INDIRECT  = 0x0100;
};
</script>

## Buffer Mapping ## {#buffer-mapping}


<script type=idl>
interface GPUBuffer : GPUObjectBase {
    Promise<ArrayBuffer> mapReadAsync();
    Promise<ArrayBuffer> mapWriteAsync();
    void unmap();

    void destroy();
};

typedef sequence<any> GPUMappedBuffer;
</script>

{{GPUMappedBuffer}} is always a sequence of 2 elements, of types {{GPUBuffer}}
and {{ArrayBuffer}}, respectively.


Textures {#textures}
====================

## GPUTexture ## {#texture}

<script type=idl>
interface GPUTexture : GPUObjectBase {
    GPUTextureView createView(optional GPUTextureViewDescriptor descriptor);

    void destroy();
};
</script>

### Texture Creation ### {#texture-creation}

<script type=idl>
dictionary GPUTextureDescriptor : GPUObjectDescriptorBase {
    required GPUExtent3D size;
    unsigned long arrayLayerCount = 1;
    unsigned long mipLevelCount = 1;
    unsigned long sampleCount = 1;
    GPUTextureDimension dimension = "2d";
    required GPUTextureFormat format;
    required GPUTextureUsageFlags usage;
};
</script>

<script type=idl>
enum GPUTextureDimension {
    "1d",
    "2d",
    "3d"
};
</script>

<script type=idl>
typedef GPUFlags GPUTextureUsageFlags;
interface GPUTextureUsage {
    const GPUFlags NONE              = 0x00;
    const GPUFlags COPY_SRC          = 0x01;
    const GPUFlags COPY_DST          = 0x02;
    const GPUFlags SAMPLED           = 0x04;
    const GPUFlags STORAGE           = 0x08;
    const GPUFlags OUTPUT_ATTACHMENT = 0x10;
};
</script>

## GPUTextureView ## {#texture-view}

<script type=idl>
interface GPUTextureView : GPUObjectBase {
};
</script>

### Texture View Creation ### {#texture-view-creation}

<script type=idl>
dictionary GPUTextureViewDescriptor : GPUObjectDescriptorBase {
    GPUTextureFormat format;
    GPUTextureViewDimension dimension;
    GPUTextureAspect aspect = "all";
    unsigned long baseMipLevel = 0;
    unsigned long mipLevelCount = 0;
    unsigned long baseArrayLayer = 0;
    unsigned long arrayLayerCount = 0;
};
</script>

<!-- TODO(kainino0x): Make this a standalone algorithm used in the createView algorithm. -->
<!-- TODO(kainino0x): The references to GPUTextureDescriptor here should actually refer to
internal slots of a [=texture=] internal object once we have one. -->

<div algorithm="resolving GPUTextureViewDescriptor defaults">

  * {{GPUTextureViewDescriptor/format}}:
    If unspecified, defaults to |texture|.{{GPUTextureDescriptor/format}}.

  * {{GPUTextureViewDescriptor/dimension}}:
    If unspecified:
      - If |texture|.{{GPUTextureDescriptor/dimension}} is {{GPUTextureDimension/"1d"}},
        defaults to {{GPUTextureViewDimension/"1d"}}.
      - If |texture|.{{GPUTextureDescriptor/dimension}} is {{GPUTextureDimension/"2d"}}:
          - If |texture|.{{GPUTextureDescriptor/arrayLayerCount}} is greater than 1
            and {{GPUTextureViewDescriptor/arrayLayerCount}} is 0,
            defaults to {{GPUTextureViewDimension/"2d-array"}}.
          - Otherwise, defaults to {{GPUTextureViewDimension/"2d"}}.
      - If |texture|.{{GPUTextureDescriptor/dimension}} is {{GPUTextureDimension/"3d"}},
        defaults to {{GPUTextureViewDimension/"3d"}}.

  * {{GPUTextureViewDescriptor/mipLevelCount}}:
    If 0, defaults to |texture|.{{GPUTextureDescriptor/mipLevelCount}} &minus; {{GPUTextureViewDescriptor/baseMipLevel}}.

  * {{GPUTextureViewDescriptor/arrayLayerCount}}:
    If 0, defaults to |texture|.{{GPUTextureDescriptor/arrayLayerCount}} &minus; {{GPUTextureViewDescriptor/baseArrayLayer}}.

</div>

<script type=idl>
enum GPUTextureViewDimension {
    "1d",
    "2d",
    "2d-array",
    "cube",
    "cube-array",
    "3d"
};
</script>

<script type=idl>
enum GPUTextureAspect {
    "all",
    "stencil-only",
    "depth-only"
};
</script>

## Texture Formats ## {#texture-formats}

The name of the format specifies the order of components, bits per component,
and data type for the component.

  * `r`, `g`, `b`, `a` = red, green, blue, alpha
  * `unorm` = unsigned normalized
  * `snorm` = signed normalized
  * `uint` = unsigned int
  * `sint` = signed int
  * `float` = floating point

If the format has the `-srgb` suffix, then sRGB gamma compression and
decompression are applied during the reading and writing of color values in the
pixel. Compressed texture formats are provided by extensions. Their naming
should follow the convention here, with the texture name as a prefix. e.g.
`etc2-rgba8unorm`.

<script type=idl>
enum GPUTextureFormat {
    // 8-bit formats
    "r8unorm",
    "r8snorm",
    "r8uint",
    "r8sint",

    // 16-bit formats
    "r16uint",
    "r16sint",
    "r16float",
    "rg8unorm",
    "rg8snorm",
    "rg8uint",
    "rg8sint",

    // 32-bit formats
    "r32uint",
    "r32sint",
    "r32float",
    "rg16uint",
    "rg16sint",
    "rg16float",
    "rgba8unorm",
    "rgba8unorm-srgb",
    "rgba8snorm",
    "rgba8uint",
    "rgba8sint",
    "bgra8unorm",
    "bgra8unorm-srgb",
    // Packed 32-bit formats
    "rgb10a2unorm",
    "rg11b10float",

    // 64-bit formats
    "rg32uint",
    "rg32sint",
    "rg32float",
    "rgba16uint",
    "rgba16sint",
    "rgba16float",

    // 128-bit formats
    "rgba32uint",
    "rgba32sint",
    "rgba32float",

    // Depth and stencil formats
    "depth32float",
    "depth24plus",
    "depth24plus-stencil8"
};
</script>

  * The `depth24plus` family of formats ({{GPUTextureFormat/depth24plus}} and
    {{GPUTextureFormat/depth24plus-stencil8}})
    must have a depth-component precision of
    1 ULP &le; 1 / (2<sup>24</sup>).

    Note: This is unlike the 24-bit unsigned normalized format family typically
    found in native APIs, which has a precision of
    1 ULP = 1 / (2<sup>24</sup> &minus; 1).

<script type=idl>
enum GPUTextureComponentType {
    "float",
    "sint",
    "uint"
};
</script>

Samplers {#samplers}
====================

## GPUSampler ## {#sampler}

<script type=idl>
interface GPUSampler : GPUObjectBase {
};
</script>

### Creation ### {#sampler-creation}

<script type=idl>
dictionary GPUSamplerDescriptor : GPUObjectDescriptorBase {
    GPUAddressMode addressModeU = "clamp-to-edge";
    GPUAddressMode addressModeV = "clamp-to-edge";
    GPUAddressMode addressModeW = "clamp-to-edge";
    GPUFilterMode magFilter = "nearest";
    GPUFilterMode minFilter = "nearest";
    GPUFilterMode mipmapFilter = "nearest";
    float lodMinClamp = 0;
    float lodMaxClamp = 0xffffffff; // TODO: What should this be? Was Number.MAX_VALUE.
    GPUCompareFunction compare = "never";
};
</script>

<script type=idl>
enum GPUAddressMode {
    "clamp-to-edge",
    "repeat",
    "mirror-repeat"
};
</script>

<script type=idl>
enum GPUFilterMode {
    "nearest",
    "linear"
};
</script>

<script type=idl>
enum GPUCompareFunction {
    "never",
    "less",
    "equal",
    "less-equal",
    "greater",
    "not-equal",
    "greater-equal",
    "always"
};
</script>


Resource Binding {#binding}
===========================

## GPUBindGroupLayout ## {#bind-group-layout}

A {{GPUBindGroupLayout}} defines the interface between a set of resources bound in a {{GPUBindGroup}} and their accessibility in shader stages.

<script type=idl>
[Serializable]
interface GPUBindGroupLayout : GPUObjectBase {
};
</script>

### Creation ### {#bind-group-layout-creation}

A {{GPUBindGroupLayout}} is created via {{GPUDevice/createBindGroupLayout()|GPUDevice.createBindGroupLayout()}}.

<script type=idl>
dictionary GPUBindGroupLayoutDescriptor : GPUObjectDescriptorBase {
    required sequence<GPUBindGroupLayoutBinding> bindings;
};
</script>

A {{GPUBindGroupLayoutBinding}} describes a single shader resource binding to be included in a {{GPUBindGroupLayout}}.

<script type=idl>
dictionary GPUBindGroupLayoutBinding {
    required unsigned long binding;
    required GPUShaderStageFlags visibility;
    required GPUBindingType type;
    GPUTextureViewDimension textureDimension = "2d";
    GPUTextureComponentType textureComponentType = "float";
    boolean multisampled = false;
    boolean hasDynamicOffset = false;
};
</script>

  * {{GPUBindGroupLayoutBinding/binding}}:
    A unique identifier for a resource binding within a {{GPUBindGroupLayoutBinding}}, a corresponding {{GPUBindGroupBinding}}, and shader stages.

  * {{GPUBindGroupLayoutBinding/visibility}}: 
    A bitset of the members of {{GPUShaderStage}}. Each set bit indicates that a {{GPUBindGroupLayoutBinding}}'s resource will be accessible from the 
    associated shader stage.

<script type=idl>
typedef GPUFlags GPUShaderStageFlags;
interface GPUShaderStage {
    const GPUFlags NONE     = 0x0;
    const GPUFlags VERTEX   = 0x1;
    const GPUFlags FRAGMENT = 0x2;
    const GPUFlags COMPUTE  = 0x4;
};
</script>

  * {{GPUBindGroupLayoutBinding/type}}: 
    A member of {{GPUBindingType}} that indicates the intended usage of a resource binding in its visible {{GPUShaderStage}}s.

<script type=idl>
enum GPUBindingType {
    "uniform-buffer",
    "storage-buffer",
    "readonly-storage-buffer",
    "sampler",
    "sampled-texture",
    "storage-texture"
    // TODO: other binding types
};
</script>

  * {{GPUBindGroupLayoutBinding/textureDimension}}, {{GPUBindGroupLayoutBinding/multisampled}}:
    Describes the dimensionality of texture view bindings, and indicates if they are multisampled.

    Note: This allows Metal-based implementations to back the respective bind
    groups with `MTLArgumentBuffer` objects that are more efficient to bind at
    run-time.

  * {{GPUBindGroupLayoutBinding/hasDynamicOffset}}:
    For {{GPUBindingType/uniform-buffer}}, {{GPUBindingType/storage-buffer}}, and {{GPUBindingType/readonly-storage-buffer}} bindings, 
    indicates that the binding has a dynamic offset. One offset must be passed to 
    setBindGroup for each dynamic binding in increasing order of
    {{GPUBindGroupLayoutBinding/binding}} number.

A {{GPUBindGroupLayout}} object has the following internal slots:

<dl dfn-type=attribute dfn-for="GPUBindGroupLayout">
	: <dfn>\[[bindings]]</dfn> of type sequence<{{GPUBindGroupLayoutBinding}}>.
	::
        The set of {{GPUBindGroupLayoutBinding}}s this {{GPUBindGroupLayout}} describes.

</dl>

### {{GPUDevice/createBindGroupLayout()|GPUDevice.createBindGroupLayout(GPUBindGroupLayoutDescriptor)}} ### {#GPUDevice-createBindGroupLayout}

<div algorithm="GPUDevice.createBindGroupLayout(descriptor)">

The <dfn-type="method" dfn-for="GPUDevice">createBindGroupLayout(|descriptor|)</dfn> method is used to create {{GPUBindGroupLayout}}s.

1. Ensure [=device validation=] is not violated.
1. Let |layout| be a new valid {{GPUBindGroupLayout}} object.
1. For each {{GPUBindGroupLayoutBinding}} |bindingDescriptor| in |descriptor|.{{GPUBindGroupLayoutDescriptor/bindings}}:
    1. Ensure |bindingDescriptor|.{{GPUBindGroupLayoutBinding/binding}} does not violate [=binding validation=].
    1. If |bindingDescriptor|.{{GPUBindGroupLayoutBinding/type}} is {{GPUBindingType/uniform-buffer}}:
        1. Ensure [=uniform buffer validation=] is not violated.
        1. If |bindingDescriptor|.{{GPUBindGroupLayoutBinding/hasDynamicOffset}} is `true`, ensure [=dynamic uniform buffer validation=] is not violated.
    1. If |bindingDescriptor|.{{GPUBindGroupLayoutBinding/type}} is {{GPUBindingType/storage-buffer}} or {{GPUBindingType/readonly-storage-buffer}}:
        1. Ensure [=storage buffer validation=] is not violated.
        1. If |bindingDescriptor|.{{GPUBindGroupLayoutBinding/hasDynamicOffset}} is `true`, ensure [=dynamic storage buffer validation=] is not violated.
    1. If |bindingDescriptor|.{{GPUBindGroupLayoutBinding/type}} is {{GPUBindingType/sampled-texture}}
        , ensure [=sampled texture validation=] is not violated.
    1. If |bindingDescriptor|.{{GPUBindGroupLayoutBinding/type}} is {{GPUBindingType/storage-texture}}
        , ensure [=storage texture validation=] is not violated.
    1. If |bindingDescriptor|.{{GPUBindGroupLayoutBinding/type}} is {{GPUBindingType/sampler}}
        , ensure [=sampler validation=] is not violated.
    1. Insert |bindingDescriptor| into |layout|.{{GPUBindGroupLayout/[[bindings]]}}.
1. Return |layout|.

<b>Validation Conditions</b>

<dl dfn-for="createBindGroupLayout(descriptor)">
If any of the following conditions are violated:
    1. Generate a {{GPUValidationError}} in the current scope with appropriate error message.
    1. Create a new invalid {{GPUBindGroupLayout}} and return the result.

<dfn>device validation</dfn>: The {{GPUDevice}} must not be lost.

<dfn>binding validation</dfn>: Each |bindingDescriptor|.{{GPUBindGroupLayoutBinding/binding}} in |descriptor| must be unique.

<dfn>uniform buffer validation</dfn>: There must be {{GPULimits/maxUniformBuffersPerShaderStage|GPULimits.maxUniformBuffersPerShaderStage}} or 
    fewer |bindingDescriptor|s of type {{GPUBindingType/uniform-buffer}} visible on each shader stage in |descriptor|.

<dfn>dynamic uniform buffer validation</dfn>: There must be {{GPULimits/maxDynamicUniformBuffersPerPipelineLayout|GPULimits.maxDynamicUniformBuffersPerPipelineLayout}} or
        fewer |bindingDescriptor|s of type {{GPUBindingType/uniform-buffer}} with {{GPUBindGroupLayoutBinding/hasDynamicOffset}} set to `true` in
        |descriptor| that are visible to any shader stage.

<dfn>storage buffer validation</dfn>: There must be {{GPULimits/maxStorageBuffersPerPipelineLayout|GPULimits.maxStorageBuffersPerPipelineLayout}} or 
    fewer |bindingDescriptor|s of type {{GPUBindingType/storage-buffer}} in |descriptor| that are visible to any shader stage.

<dfn>dynamic storage buffer validation</dfn>: There must be {{GPULimits/maxDynamicStorageBuffersPerPipelineLayout|GPULimits.maxDynamicStorageBuffersPerPipelineLayout}} or
        fewer |bindingDescriptor|s of type {{GPUBindingType/storage-buffer}} with {{GPUBindGroupLayoutBinding/hasDynamicOffset}} set to `true` 
        in |descriptor| that are visible to any shader stage.

<dfn>sampled texture validation</dfn>: There must be {{GPULimits/maxSampledTexturesPerShaderStage|GPULimits.maxSampledTexturesPerShaderStage}} or 
    fewer |bindingDescriptor|s of type {{GPUBindingType/sampled-texture}} visible on each shader stage in |descriptor|.

<dfn>storage texture validation</dfn>: There must be {{GPULimits/maxStorageTexturesPerShaderStage|GPULimits.maxStorageTexturesPerShaderStage}} or 
    fewer |bindingDescriptor|s of type {{GPUBindingType/storage-texture}} visible on each shader stage in |descriptor|.

<dfn>sampler validation</dfn>: There must be {{GPULimits/maxSamplersPerShaderStage|GPULimits.maxSamplersPerShaderStage}} or 
    fewer |bindingDescriptor|s of type {{GPUBindingType/sampler}} visible on each shader stage in |descriptor|.

</dl>
</div>

## GPUBindGroup ## {#bind-groups}

<script type=idl>
interface GPUBindGroup : GPUObjectBase {
};
</script>

### Bind Group Creation ### {#bind-group-creation}

<script type=idl>
dictionary GPUBindGroupDescriptor : GPUObjectDescriptorBase {
    required GPUBindGroupLayout layout;
    required sequence<GPUBindGroupBinding> bindings;
};
</script>

<script type=idl>
typedef (GPUSampler or GPUTextureView or GPUBufferBinding) GPUBindingResource;

dictionary GPUBindGroupBinding {
    required unsigned long binding;
    required GPUBindingResource resource;
};
</script>

<script type=idl>
dictionary GPUBufferBinding {
    required GPUBuffer buffer;
    GPUBufferSize offset = 0;
    GPUBufferSize size;
};
</script>

  * {{GPUBufferBinding/size}}: If undefined, specifies the range starting at {{GPUBufferBinding/offset}} and ending at the end of the buffer.

## GPUPipelineLayout ## {#pipeline-layout}

<script type=idl>
interface GPUPipelineLayout : GPUObjectBase {
};
</script>

### Creation ### {#pipeline-layout-creation}

<script type=idl>
dictionary GPUPipelineLayoutDescriptor : GPUObjectDescriptorBase {
    required sequence<GPUBindGroupLayout> bindGroupLayouts;
};
</script>

Shader Modules {#shader-modules}
================================

## GPUShaderModule ## {#shader-module}

<script type=idl>
[Serializable]
interface GPUShaderModule : GPUObjectBase {
};
</script>

{{GPUShaderModule}} is {{Serializable}}. It is a reference to an internal
shader module object, and {{Serializable}} means that the reference can be
*copied* between realms (threads/workers), allowing multiple realms to access
it concurrently. Since {{GPUShaderModule}} immutable, there are no race
conditions.

### Shader Module Creation ### {#shader-module-creation}

<script type=idl>
typedef (Uint32Array or DOMString) GPUShaderCode;

dictionary GPUShaderModuleDescriptor : GPUObjectDescriptorBase {
    required GPUShaderCode code;
};
</script>

Note: While the choice of shader language is undecided,
`GPUShaderModuleDescriptor` will temporarily accept both text and binary input.


Pipelines {#pipelines}
======================

<script type=idl>
dictionary GPUPipelineDescriptorBase : GPUObjectDescriptorBase {
    required GPUPipelineLayout layout;
};
</script>

<script type=idl>
dictionary GPUProgrammableStageDescriptor {
    required GPUShaderModule module;
    required DOMString entryPoint;
    // TODO: other stuff like specialization constants?
};
</script>

## GPUComputePipeline ## {#compute-pipeline}

<script type=idl>
[Serializable]
interface GPUComputePipeline : GPUObjectBase {
};
</script>

### Creation ### {#compute-pipeline-creation}

<script type=idl>
dictionary GPUComputePipelineDescriptor : GPUPipelineDescriptorBase {
    required GPUProgrammableStageDescriptor computeStage;
};
</script>

## GPURenderPipeline ## {#render-pipeline}

<script type=idl>
[Serializable]
interface GPURenderPipeline : GPUObjectBase {
};
</script>

### Creation ### {#render-pipeline-creation}

<script type=idl>
dictionary GPURenderPipelineDescriptor : GPUPipelineDescriptorBase {
    required GPUProgrammableStageDescriptor vertexStage;
    GPUProgrammableStageDescriptor fragmentStage;

    required GPUPrimitiveTopology primitiveTopology;
    GPURasterizationStateDescriptor rasterizationState;
    required sequence<GPUColorStateDescriptor> colorStates;
    GPUDepthStencilStateDescriptor depthStencilState;
    GPUVertexInputDescriptor vertexInput = {};

    unsigned long sampleCount = 1;
    unsigned long sampleMask = 0xFFFFFFFF;
    boolean alphaToCoverageEnabled = false;
    // TODO: other properties
};
</script>

  * {{GPURenderPipelineDescriptor/sampleCount}}: Number of MSAA samples.

### Primitive Topology ### {#primitive-topology}

<script type=idl>
enum GPUPrimitiveTopology {
    "point-list",
    "line-list",
    "line-strip",
    "triangle-list",
    "triangle-strip"
};
</script>

### Rasterization State ### {#rasterization-state}

<script type=idl>
dictionary GPURasterizationStateDescriptor {
    GPUFrontFace frontFace = "ccw";
    GPUCullMode cullMode = "none";

    long depthBias = 0;
    float depthBiasSlopeScale = 0;
    float depthBiasClamp = 0;
};
</script>

<script type=idl>
enum GPUFrontFace {
    "ccw",
    "cw"
};
</script>

<script type=idl>
enum GPUCullMode {
    "none",
    "front",
    "back"
};
</script>

### Color State ### {#color-state}

<script type=idl>
dictionary GPUColorStateDescriptor {
    required GPUTextureFormat format;

    GPUBlendDescriptor alphaBlend;
    GPUBlendDescriptor colorBlend;
    GPUColorWriteFlags writeMask = 0xF;  // GPUColorWrite.ALL
};
</script>

<script type=idl>
typedef GPUFlags GPUColorWriteFlags;
interface GPUColorWrite {
    const GPUFlags NONE  = 0x0;
    const GPUFlags RED   = 0x1;
    const GPUFlags GREEN = 0x2;
    const GPUFlags BLUE  = 0x4;
    const GPUFlags ALPHA = 0x8;
    const GPUFlags ALL   = 0xF;
};
</script>

#### Blend State #### {#blend-state}

<script type=idl>
dictionary GPUBlendDescriptor {
    GPUBlendFactor srcFactor = "one";
    GPUBlendFactor dstFactor = "zero";
    GPUBlendOperation operation = "add";
};
</script>

<script type=idl>
enum GPUBlendFactor {
    "zero",
    "one",
    "src-color",
    "one-minus-src-color",
    "src-alpha",
    "one-minus-src-alpha",
    "dst-color",
    "one-minus-dst-color",
    "dst-alpha",
    "one-minus-dst-alpha",
    "src-alpha-saturated",
    "blend-color",
    "one-minus-blend-color"
};
</script>

<script type=idl>
enum GPUBlendOperation {
    "add",
    "subtract",
    "reverse-subtract",
    "min",
    "max"
};
</script>

<script type=idl>
enum GPUStencilOperation {
    "keep",
    "zero",
    "replace",
    "invert",
    "increment-clamp",
    "decrement-clamp",
    "increment-wrap",
    "decrement-wrap"
};
</script>

### Depth/Stencil State ### {#depth-stencil-state}

<script type=idl>
dictionary GPUDepthStencilStateDescriptor {
    required GPUTextureFormat format;

    boolean depthWriteEnabled = false;
    GPUCompareFunction depthCompare = "always";

    required GPUStencilStateFaceDescriptor stencilFront;
    required GPUStencilStateFaceDescriptor stencilBack;

    unsigned long stencilReadMask = 0xFFFFFFFF;
    unsigned long stencilWriteMask = 0xFFFFFFFF;
};
</script>

<script type=idl>
dictionary GPUStencilStateFaceDescriptor {
    GPUCompareFunction compare = "always";
    GPUStencilOperation failOp = "keep";
    GPUStencilOperation depthFailOp = "keep";
    GPUStencilOperation passOp = "keep";
};
</script>

### Vertex Input ### {#vertex-input}

<script type=idl>
enum GPUIndexFormat {
    "uint16",
    "uint32"
};
</script>

#### Vertex formats #### {#vertex-formats}

The name of the format specifies the data type of the component, the number of
values, and whether the data is normalized.

  * `uchar` = unsigned 8-bit value
  * `char` = signed 8-bit value
  * `ushort` = unsigned 16-bit value
  * `short` = signed 16-bit value
  * `half` = half-precision 16-bit floating point value
  * `float` = 32-bit floating point value
  * `uint` = unsigned 32-bit integer value
  * `int` = signed 32-bit integer value

If no number of values is given in the name, a single value is provided.
If the format has the `-bgra` suffix, it means the values are arranged as
blue, green, red and alpha values.

<script type=idl>
enum GPUVertexFormat {
    "uchar2",
    "uchar4",
    "char2",
    "char4",
    "uchar2norm",
    "uchar4norm",
    "char2norm",
    "char4norm",
    "ushort2",
    "ushort4",
    "short2",
    "short4",
    "ushort2norm",
    "ushort4norm",
    "short2norm",
    "short4norm",
    "half2",
    "half4",
    "float",
    "float2",
    "float3",
    "float4",
    "uint",
    "uint2",
    "uint3",
    "uint4",
    "int",
    "int2",
    "int3",
    "int4"
};
</script>

<script type=idl>
enum GPUInputStepMode {
    "vertex",
    "instance"
};
</script>

<script type=idl>
dictionary GPUVertexAttributeDescriptor {
    GPUBufferSize offset = 0;
    required GPUVertexFormat format;
    required unsigned long shaderLocation;
};
</script>

<script type=idl>
dictionary GPUVertexBufferDescriptor {
    required GPUBufferSize stride;
    GPUInputStepMode stepMode = "vertex";
    required sequence<GPUVertexAttributeDescriptor> attributeSet;
};
</script>

<script type=idl>
dictionary GPUVertexInputDescriptor {
    GPUIndexFormat indexFormat = "uint32";
    sequence<GPUVertexBufferDescriptor?> vertexBuffers = [];
};
</script>


Command Buffers {#command-buffers}
==================================

## GPUCommandBuffer ## {#command-buffer}

<script type=idl>
interface GPUCommandBuffer : GPUObjectBase {
};
</script>

### Creation ### {#command-buffer-creation}

<script type=idl>
dictionary GPUCommandBufferDescriptor : GPUObjectDescriptorBase {
};
</script>


Command Encoding {#command-encoding}
====================================

## GPUCommandEncoder ## {#command-encoder}

<script type=idl>
interface GPUCommandEncoder : GPUObjectBase {
    GPURenderPassEncoder beginRenderPass(GPURenderPassDescriptor descriptor);
    GPUComputePassEncoder beginComputePass(optional GPUComputePassDescriptor descriptor);

    void copyBufferToBuffer(
        GPUBuffer source,
        GPUBufferSize sourceOffset,
        GPUBuffer destination,
        GPUBufferSize destinationOffset,
        GPUBufferSize size);

    void copyBufferToTexture(
        GPUBufferCopyView source,
        GPUTextureCopyView destination,
        GPUExtent3D copySize);

    void copyTextureToBuffer(
        GPUTextureCopyView source,
        GPUBufferCopyView destination,
        GPUExtent3D copySize);

    void copyTextureToTexture(
        GPUTextureCopyView source,
        GPUTextureCopyView destination,
        GPUExtent3D copySize);

    void copyImageBitmapToTexture(
        GPUImageBitmapCopyView source,
        GPUTextureCopyView destination,
        GPUExtent3D copySize);

    void pushDebugGroup(DOMString groupLabel);
    void popDebugGroup();
    void insertDebugMarker(DOMString markerLabel);

    GPUCommandBuffer finish(optional GPUCommandBufferDescriptor descriptor);
};
</script>

  * {{GPUCommandEncoder/copyImageBitmapToTexture()}}:
      * For now, `copySize.z` must be `1`.

### Creation ### {#command-encoder-creation}

<script type=idl>
dictionary GPUCommandEncoderDescriptor : GPUObjectDescriptorBase {
    // TODO: reusability flag?
};
</script>

## Copy Commands ## {#copy-commands}

<script type=idl>
dictionary GPUBufferCopyView {
    required GPUBuffer buffer;
    GPUBufferSize offset = 0;
    required unsigned long rowPitch;
    required unsigned long imageHeight;
};
</script>

<script type=idl>
dictionary GPUTextureCopyView {
    required GPUTexture texture;
    unsigned long mipLevel = 0;
    unsigned long arrayLayer = 0;
    GPUOrigin3D origin;
};
</script>

  * {{GPUTextureCopyView/origin}}: If unspecified, defaults to `[0, 0, 0]`.

<script type=idl>
dictionary GPUImageBitmapCopyView {
    required ImageBitmap imageBitmap;
    GPUOrigin2D origin;
};
</script>

  * {{GPUImageBitmapCopyView/origin}}: If unspecified, defaults to `[0, 0]`.

## Programmable Passes ## {#programmable-passes}

<script type=idl>
interface GPUProgrammablePassEncoder : GPUObjectBase {
    void setBindGroup(unsigned long index, GPUBindGroup bindGroup,
                      optional sequence<GPUBufferSize> dynamicOffsets);

    void pushDebugGroup(DOMString groupLabel);
    void popDebugGroup();
    void insertDebugMarker(DOMString markerLabel);
};
</script>

Debug groups in a {{GPUCommandEncoder}} or {{GPUProgrammablePassEncoder}}
must be well nested.

Compute Passes {#compute-passes}
================================

## GPUComputePassEncoder ## {#compute-pass-encoder}

<script type=idl>
interface GPUComputePassEncoder : GPUProgrammablePassEncoder {
    void setPipeline(GPUComputePipeline pipeline);
    void dispatch(unsigned long x, optional unsigned long y = 1, optional unsigned long z = 1);
    void dispatchIndirect(GPUBuffer indirectBuffer, GPUBufferSize indirectOffset);

    void endPass();
};
</script>

### Creation ### {#compute-pass-encoder-creation}

<script type=idl>
dictionary GPUComputePassDescriptor : GPUObjectDescriptorBase {
};
</script>

Render Passes {#render-passes}
==============================

## GPURenderPassEncoder ## {#render-pass-encoder}

<script type=idl>
interface GPURenderEncoderBase : GPUProgrammablePassEncoder {
    void setPipeline(GPURenderPipeline pipeline);

    void setIndexBuffer(GPUBuffer buffer, optional GPUBufferSize offset = 0);
    void setVertexBuffers(unsigned long startSlot,
                          sequence<GPUBuffer> buffers, sequence<GPUBufferSize> offsets);

    void draw(unsigned long vertexCount, unsigned long instanceCount,
              unsigned long firstVertex, unsigned long firstInstance);
    void drawIndexed(unsigned long indexCount, unsigned long instanceCount,
                     unsigned long firstIndex, long baseVertex, unsigned long firstInstance);

    void drawIndirect(GPUBuffer indirectBuffer, GPUBufferSize indirectOffset);
    void drawIndexedIndirect(GPUBuffer indirectBuffer, GPUBufferSize indirectOffset);
};

interface GPURenderPassEncoder : GPURenderEncoderBase {
    void setViewport(float x, float y,
                     float width, float height,
                     float minDepth, float maxDepth);

    void setScissorRect(unsigned long x, unsigned long y, unsigned long width, unsigned long height);

    void setBlendColor(GPUColor color);
    void setStencilReference(unsigned long reference);

    void executeBundles(sequence<GPURenderBundle> bundles);
    void endPass();
};
</script>

  * In indirect draw calls, the base instance field (inside the indirect
    buffer data) must be set to zero.

  * {{GPURenderPassEncoder/setScissorRect()}}:
      * An error is generated if `width` or `height` is not greater than 0.

When a {{GPURenderPassEncoder}} is created, it has the following default state:
  * Viewport:
      * `x, y` = `0.0, 0.0`
      * `width, height` = the dimensions of the pass's render targets
      * `minDepth, maxDepth` = `0.0, 1.0`
  * Scissor rectangle:
      * `x, y` = `0, 0`
      * `width, height` = the dimensions of the pass's render targets

When a {{GPURenderBundle}} is executed, it does not inherit the pass's pipeline,
bind groups, or vertex or index buffers. After a {{GPURenderBundle}} has executed,
the pass's pipeline, bind groups, and vertex and index buffers are cleared. If zero
{{GPURenderBundle}}s are executed, the command buffer state is unchanged.

### Creation ### {#render-pass-encoder-creation}

<script type=idl>
dictionary GPURenderPassDescriptor : GPUObjectDescriptorBase {
    required sequence<GPURenderPassColorAttachmentDescriptor> colorAttachments;
    GPURenderPassDepthStencilAttachmentDescriptor depthStencilAttachment;
};
</script>

#### Color Attachments #### {#color-attachments}

<script type=idl>
dictionary GPURenderPassColorAttachmentDescriptor {
    required GPUTextureView attachment;
    GPUTextureView resolveTarget;

    required (GPULoadOp or GPUColor) loadValue;
    GPUStoreOp storeOp = "store";
};
</script>

#### Depth/Stencil Attachments #### {#depth-stencil-attachments}

<script type=idl>
dictionary GPURenderPassDepthStencilAttachmentDescriptor {
    required GPUTextureView attachment;

    required (GPULoadOp or float) depthLoadValue;
    required GPUStoreOp depthStoreOp;

    required (GPULoadOp or unsigned long) stencilLoadValue;
    required GPUStoreOp stencilStoreOp;
};
</script>

### Load &amp Store Operations ### {#load-and-store-ops}

<script type=idl>
enum GPULoadOp {
    "load"
};
</script>

<script type=idl>
enum GPUStoreOp {
    "store",
    "clear"
};
</script>


Bundles {#bundles}
==================

## GPURenderBundle ## {#render-bundle}

<script type=idl>
interface GPURenderBundle : GPUObjectBase {
};
</script>

### Creation ### {#render-bundle-creation}

<script type=idl>
dictionary GPURenderBundleDescriptor : GPUObjectDescriptorBase {
};
</script>

<script type=idl>
interface GPURenderBundleEncoder : GPURenderEncoderBase {
    GPURenderBundle finish(optional GPURenderBundleDescriptor descriptor);
};
</script>

### Encoding ### {#render-bundle-encoding}

<script type=idl>
dictionary GPURenderBundleEncoderDescriptor : GPUObjectDescriptorBase {
    required sequence<GPUTextureFormat> colorFormats;
    GPUTextureFormat depthStencilFormat;
    unsigned long sampleCount = 1;
};
</script>


Queues {#queues}
================

<script type=idl>
interface GPUQueue : GPUObjectBase {
    void submit(sequence<GPUCommandBuffer> buffers);

    GPUFence createFence(optional GPUFenceDescriptor descriptor);
    void signal(GPUFence fence, unsigned long long signalValue);
};
</script>

## GPUFence ## {#fence}

<script type=idl>
interface GPUFence : GPUObjectBase {
    unsigned long long getCompletedValue();
    Promise<void> onCompletion(unsigned long long completionValue);
};
</script>

### Creation ### {#fence-creation}

<script type=idl>
dictionary GPUFenceDescriptor : GPUObjectDescriptorBase {
    unsigned long long initialValue = 0;
};
</script>


Canvas Rendering and Swap Chain {#swapchain}
============================================

<script type=idl>
interface GPUCanvasContext {
    GPUSwapChain configureSwapChain(GPUSwapChainDescriptor descriptor);

    Promise<GPUTextureFormat> getSwapChainPreferredFormat(GPUDevice device);
};
</script>

  * {{GPUCanvasContext/configureSwapChain()}}:
    Configures the swap chain for this canvas, and returns a new
    {{GPUSwapChain}} object representing it. Destroys any swapchain
    previously returned by `configureSwapChain`, including all of the
    textures it has produced.

<script type=idl>
dictionary GPUSwapChainDescriptor : GPUObjectDescriptorBase {
    required GPUDevice device;
    required GPUTextureFormat format;
    GPUTextureUsageFlags usage = 0x10;  // GPUTextureUsage.OUTPUT_ATTACHMENT
};
</script>

<script type=idl>
interface GPUSwapChain : GPUObjectBase {
    GPUTexture getCurrentTexture();
};
</script>


Errors &amp; Debugging {#errors-and-debugging}
==============================================

## Fatal Errors ## {#fatal-errors}

<script type=idl>
interface GPUDeviceLostInfo {
    readonly attribute DOMString message;
};

partial interface GPUDevice {
    readonly attribute Promise<GPUDeviceLostInfo> lost;
};
</script>


## Error Scopes ## {#error-scopes}

<script type=idl>
enum GPUErrorFilter {
    "none",
    "out-of-memory",
    "validation"
};
</script>

<script type=idl>
[
    Constructor()
]
interface GPUOutOfMemoryError {};

[
    Constructor(DOMString message)
]
interface GPUValidationError {
    readonly attribute DOMString message;
};

typedef (GPUOutOfMemoryError or GPUValidationError) GPUError;
</script>

<script type=idl>
partial interface GPUDevice {
    void pushErrorScope(GPUErrorFilter filter);
    Promise<GPUError?> popErrorScope();
};
</script>

{{GPUDevice/popErrorScope()}} throws {{OperationError}} if there are no error scopes on the stack.


## Telemetry ## {#telemetry}

<script type=idl>
[
    Constructor(DOMString type, GPUUncapturedErrorEventInit gpuUncapturedErrorEventInitDict),
    Exposed=Window
]
interface GPUUncapturedErrorEvent : Event {
    readonly attribute GPUError error;
};

dictionary GPUUncapturedErrorEventInit : EventInit {
    required GPUError error;
};
</script>

<script type=idl>
partial interface GPUDevice {
    [Exposed=Window]
    attribute EventHandler onuncapturederror;
};
</script>

# Temporary usages of non-exported dfns ## {#temp-dfn-usages}

Eventually all of these should disappear but they are useful to avoid warning while building the specification.

[=buffer state/mapped=] [=buffer state/destroyed=]
